﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;

namespace Apq.Data
{
	/// <summary>
	/// 公用模块
	/// </summary>
	public class Common
	{
		/// <summary>
		/// 对于不支持的来源类型返回的默认值
		/// </summary>
		public static string NonSupportedInType = "'<不支持的来源类型>'";
		/// <summary>
		/// 对于不支持的目标类型返回的默认值
		/// </summary>
		public static string NonSupportedOutType = "'<不支持的输出类型>'";

		#region ht Db ==> CS
		private static Dictionary<DbType, Type> _htDbToCS = null;
		/// <summary>
		/// 获取SQL数据库类型与C#类型的对应表
		/// </summary>
		protected static Dictionary<DbType, Type> htDbToCS
		{
			get
			{
				if (_htDbToCS == null)
				{
					_htDbToCS = new Dictionary<DbType, Type>();

					_htDbToCS.Add(DbType.AnsiString, typeof(string));
					_htDbToCS.Add(DbType.AnsiStringFixedLength, typeof(string));
					_htDbToCS.Add(DbType.String, typeof(string));
					_htDbToCS.Add(DbType.StringFixedLength, typeof(string));

					_htDbToCS.Add(DbType.Binary, typeof(byte[]));

					_htDbToCS.Add(DbType.Boolean, typeof(bool));
					_htDbToCS.Add(DbType.Byte, typeof(byte));
					_htDbToCS.Add(DbType.SByte, typeof(sbyte));

					_htDbToCS.Add(DbType.Currency, typeof(decimal));
					_htDbToCS.Add(DbType.Decimal, typeof(decimal));
					_htDbToCS.Add(DbType.Double, typeof(double));
					_htDbToCS.Add(DbType.Single, typeof(float));
					_htDbToCS.Add(DbType.VarNumeric, typeof(decimal));

					_htDbToCS.Add(DbType.Date, typeof(DateTime));
					_htDbToCS.Add(DbType.DateTime, typeof(DateTime));
					_htDbToCS.Add(DbType.DateTime2, typeof(DateTime));
					_htDbToCS.Add(DbType.Time, typeof(DateTime));
					_htDbToCS.Add(DbType.DateTimeOffset, typeof(System.DateTimeOffset));

					_htDbToCS.Add(DbType.Guid, typeof(Guid));

					_htDbToCS.Add(DbType.Int16, typeof(short));
					_htDbToCS.Add(DbType.Int32, typeof(int));
					_htDbToCS.Add(DbType.Int64, typeof(long));
					_htDbToCS.Add(DbType.UInt16, typeof(ushort));
					_htDbToCS.Add(DbType.UInt32, typeof(uint));
					_htDbToCS.Add(DbType.UInt64, typeof(ulong));

					_htDbToCS.Add(DbType.Xml, typeof(System.Xml.XmlDocument));
				}
				return _htDbToCS;
			}
		}

		/// <summary>
		/// 获取数据库类型对应的C#类型
		/// </summary>
		/// <param name="sdt"></param>
		/// <returns></returns>
		public static Type GetCSType(DbType sdt)
		{
			Type t = typeof(string);
			if (htDbToCS.ContainsKey(sdt))
			{
				t = htDbToCS[sdt];
			}
			return t;
		}
		#endregion

		#region ht CS ==> Db
		private static Dictionary<Type, DbType> _htCSToDb = null;
		/// <summary>
		/// 获取C#类型与SQL数据库类型的对应表
		/// </summary>
		protected static Dictionary<Type, DbType> htCSToDb
		{
			get
			{
				if (_htCSToDb == null)
				{
					_htCSToDb = new Dictionary<Type, DbType>();
					_htCSToDb.Add(typeof(bool), DbType.Boolean);
					_htCSToDb.Add(typeof(byte), DbType.Byte);
					_htCSToDb.Add(typeof(byte[]), DbType.Binary);
					_htCSToDb.Add(typeof(DateTime), DbType.DateTime);
					_htCSToDb.Add(typeof(System.DateTimeOffset), DbType.DateTimeOffset);
					_htCSToDb.Add(typeof(decimal), DbType.Decimal);
					_htCSToDb.Add(typeof(double), DbType.Double);
					_htCSToDb.Add(typeof(float), DbType.Single);
					_htCSToDb.Add(typeof(Guid), DbType.Guid);
					_htCSToDb.Add(typeof(int), DbType.Int32);
					_htCSToDb.Add(typeof(long), DbType.Int64);
					_htCSToDb.Add(typeof(sbyte), DbType.SByte);
					_htCSToDb.Add(typeof(short), DbType.Int16);
					_htCSToDb.Add(typeof(string), DbType.String);
					_htCSToDb.Add(typeof(System.Xml.XmlDocument), DbType.Xml);
					_htCSToDb.Add(typeof(uint), DbType.UInt32);
					_htCSToDb.Add(typeof(ulong), DbType.UInt64);
					_htCSToDb.Add(typeof(ushort), DbType.UInt16);
				}
				return _htCSToDb;
			}
		}

		/// <summary>
		/// 获取C#类型对应的数据库类型
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		public static DbType GetDbType(Type t)
		{
			DbType sdt = DbType.String;
			if (htCSToDb.ContainsKey(t))
			{
				sdt = htCSToDb[t];
			}
			return sdt;
		}
		#endregion

		#region EncodeString
		/// <summary>
		/// 对字符串编码
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public static string EncodeString(string str)
		{
			return str.Replace("'", "''");
		}
		#endregion

		#region ConvertToSqlON

		/// <summary>
		/// 获取 SQL 语句常量表示串
		/// </summary>
		/// <param name="sdt">已支持类型受限于下级方法实现</param>
		/// <param name="obj"></param>
		/// <returns></returns>
		public static string ConvertToSqlON(System.Data.DbType sdt, object obj)
		{
			System.ValueType val = obj as System.ValueType;
			if (val != null)
			{	// 值类型
				string rtn = ConvertToSqlON(sdt, val);
				return rtn;
			}
			else
			{	// 以下为引用类型处理
				#region DBNull
				DBNull dbNull = obj as DBNull;
				if (dbNull != null)
				{
					return "NULL";
				}
				#endregion

				#region string
				string str = obj as string;
				if (str != null)
				{
					string rtn = ConvertToSqlON(sdt, str);
					return rtn;
				}
				#endregion

				#region byte[]
				byte[] aryBytes = obj as byte[];
				if (aryBytes != null)
				{
					string rtn = ConvertToSqlON(sdt, aryBytes);
					return rtn;
				}
				#endregion
			}

			return NonSupportedInType;
		}

		/// <summary>
		/// 获取 SQL 语句常量表示串
		/// </summary>
		/// <param name="sdt">已支持类型受限于下级方法实现</param>
		/// <param name="val"></param>
		/// <returns></returns>
		public static string ConvertToSqlON(System.Data.DbType sdt, System.ValueType val)
		{
			#region bool || byte
			if (val is bool || val is byte)
			{
				int n = System.Convert.ToInt32(val);
				string rtn = ConvertToSqlON(sdt, n);
				return rtn.ToString();
			}
			#endregion

			#region 默认处理方式
			if (sdt == System.Data.DbType.Currency
				|| sdt == System.Data.DbType.Decimal
				|| sdt == System.Data.DbType.Double
				|| sdt == System.Data.DbType.Int16
				|| sdt == System.Data.DbType.Int32
				|| sdt == System.Data.DbType.Int64
				|| sdt == System.Data.DbType.Single
				|| sdt == System.Data.DbType.UInt16
				|| sdt == System.Data.DbType.UInt32
				|| sdt == System.Data.DbType.UInt64
				|| sdt == System.Data.DbType.VarNumeric
			)
			{
				string rtn = val.ToString();
				return rtn;
			}

			if (sdt == System.Data.DbType.AnsiString
				|| sdt == System.Data.DbType.AnsiStringFixedLength
				|| sdt == System.Data.DbType.Date
				|| sdt == System.Data.DbType.DateTime
				|| sdt == System.Data.DbType.DateTime2
				|| sdt == System.Data.DbType.DateTimeOffset
				|| sdt == System.Data.DbType.Guid
				|| sdt == System.Data.DbType.String
				|| sdt == System.Data.DbType.StringFixedLength
				|| sdt == System.Data.DbType.Time
			)
			{
				string str = val.ToString();
				string rtn = ConvertToSqlON(sdt, str);
				return rtn;
			}
			#endregion

			return NonSupportedOutType;
		}

		/// <summary>
		/// 获取 SQL 语句常量表示串
		/// </summary>
		/// <param name="sdt">{Char,DateTime,NChar,NText,NVarChar,SmallDateTime,Text,UniqueIdentifier,VarChar}</param>
		/// <param name="str"></param>
		/// <returns></returns>
		public static string ConvertToSqlON(System.Data.DbType sdt, string str)
		{
			if (sdt == System.Data.DbType.AnsiString
				|| sdt == System.Data.DbType.AnsiStringFixedLength
				|| sdt == System.Data.DbType.Date
				|| sdt == System.Data.DbType.DateTime
				|| sdt == System.Data.DbType.DateTime2
				|| sdt == System.Data.DbType.DateTimeOffset
				|| sdt == System.Data.DbType.Guid
				|| sdt == System.Data.DbType.String
				|| sdt == System.Data.DbType.StringFixedLength
				|| sdt == System.Data.DbType.Time
			)
			{	// 需要在前后添加单引号(')
				string rtn = "'" + EncodeString(str) + "'";

				if (sdt == System.Data.DbType.String
					|| sdt == System.Data.DbType.StringFixedLength
				)
				{
					rtn = "N" + rtn;
				}
				return rtn;
			}
			return NonSupportedOutType;
		}

		/// <summary>
		/// 获取 SQL 语句常量表示串
		/// </summary>
		/// <param name="sdt">{Binary,Bit,Image,Variant,UniqueIdentifier}</param>
		/// <param name="ary"></param>
		/// <returns></returns>
		public static string ConvertToSqlON(System.Data.DbType sdt, params byte[] ary)
		{
			string rtn = NonSupportedOutType;
			if (sdt == System.Data.DbType.Binary)
			{
				rtn = string.Empty;
				foreach (byte b in ary)
				{
					string str = System.Convert.ToString(b, 16);
					if (str.Length < 2)
					{
						str = "0" + str;
					}
					rtn += str;
				}
				rtn = "0x" + rtn;
			}
			else if (sdt == System.Data.DbType.Guid)
			{	// 需要在前后添加单引号(')
				rtn = "'";
				for (int i = 0; i < 4; i++)
				{
					rtn += System.Convert.ToString(ary[i], 16);
				}
				rtn += "-";
				for (int i = 4; i < 6; i++)
				{
					rtn += System.Convert.ToString(ary[i], 16);
				}
				rtn += "-";
				for (int i = 6; i < 8; i++)
				{
					rtn += System.Convert.ToString(ary[i], 16);
				}
				rtn += "-";
				for (int i = 8; i < 10; i++)
				{
					rtn += System.Convert.ToString(ary[i], 16);
				}
				rtn += "-";
				for (int i = 10; i < 16; i++)
				{
					rtn += System.Convert.ToString(ary[i], 16);
				}
				rtn += "'";
			}
			return rtn;
		}

		/// <summary>
		/// 根据传入对象类型,获取对应的 SQL 语句常量表示串
		/// </summary>
		/// <returns></returns>
		public static string ConvertToSqlON(object obj)
		{
			DbType sdt = GetDbType(obj.GetType());
			string rtn = ConvertToSqlON(sdt, obj);
			return rtn;
		}

		/// <summary>
		/// 根据传入行数据,获取对应的 SQL 语句常量表示串
		/// </summary>
		/// <returns></returns>
		public static string ConvertToSqlON(DataRow dr)
		{
			List<string> lst = new List<string>();

			for (int i = 0; i < dr.Table.Columns.Count; i++)
			{
				lst.Add(ConvertToSqlON(dr[i]));
			}

			return string.Join(",", lst);
		}
		#endregion

		#region ParseSqlON
		/// <summary>
		/// 解析 SqlON 对象
		/// </summary>
		/// <typeparam name="T">解析结果目标类型</typeparam>
		/// <param name="rtn">解析出来的结果</param>
		/// <param name="sdt">来源类型</param>
		/// <param name="SqlON">来源 SqlON 字符串</param>
		/// <returns></returns>
		public static bool ParseSqlON<T>(ref object rtn, System.Data.DbType sdt, string SqlON)
		{
			bool Parsed = true;

			#region byte[]
			if (typeof(T) == typeof(byte[]))
			{
				switch (sdt)
				{
					// 以 0x 开头
					case DbType.Binary:
						byte[] rtn1 = new byte[(SqlON.Length - 2) / 2];
						for (int i = 0; i < rtn1.Length; i++)
						{
							rtn1[i] = System.Convert.ToByte(SqlON.Substring(2 * (i + 1), 2), 16);
						}
						rtn = rtn1;
						break;

					// 放在 '' 之间
					case DbType.AnsiString:
					case DbType.AnsiStringFixedLength:
					case DbType.String:
					case DbType.StringFixedLength:
					case DbType.DateTime:
					case DbType.Date:
					case DbType.Time:
					case DbType.DateTime2:
					case DbType.DateTimeOffset:
					case DbType.Guid:
						string str = SqlON.Trim().Substring(1, SqlON.Length - 2).Replace("''", "'");
						byte[] rtn2 = System.Text.Encoding.Unicode.GetBytes(str);
						rtn = rtn2;
						break;

					// 10进制整数(有符号)
					case DbType.Int16:
					case DbType.Int32:
					case DbType.Int64:
						long rtn3 = System.Convert.ToInt64(SqlON);
						rtn = rtn3;
						break;

					// 10进制整数(无符号)
					case DbType.UInt16:
					case DbType.UInt32:
					case DbType.UInt64:
						ulong rtn4 = System.Convert.ToUInt64(SqlON);
						rtn = rtn4;
						break;

					// 10进制小数
					case DbType.Decimal:
					case DbType.Single:
					case DbType.Currency:
					case DbType.Double:
					case DbType.VarNumeric:
						double rtn5 = System.Convert.ToDouble(SqlON);
						rtn = rtn5;
						break;

					default:
						Parsed = false;
						break;
				}
			}
			#endregion

			return Parsed;
		}
		#endregion
	}
}
